class BlackDeathHeroPawn extends BlackDeathPawn
	placeable;

//camera varibles
var vector CamOffset;
var vector CurrentCamLoc;
var Rotator CurrentCamRot;

var() float	UseableCheckRadius;

/** test varible, keeps track of a temp sword socket */
var name SwordHolderSocket;

/** Running Varibles */
//Determines the maximum Stamina that player can have
var int StaminaMax;

var int Stamina;//current stamina
var bool bForceFullCooldown;//Do we have to wiat for full colldown to run?

//Hold enumeration for what health state we're in
enum EHealthState
{
	EHS_Excellent,
	EHS_Fair,
	EHS_Bad,
	EHS_Dead
};

var int ExcellentMinHealth;//Minimum Health for the excellent Health state
var int FairMinHealth;//Minimum Health for the Good health state
//The current health level of the player
var EHealthState CurrentHealthState;

var int LocalHealthMax;//Max health for current health level
//Scalar for how much the camera should tilt with damage.
var float TiltDamageScale;


//END VARIBLES


simulated function PostBeginPlay()
{
	super.PostBeginPlay();
	Stamina = StaminaMax;
	//Health = HealthMax;
	LocalHealthMax = HealthMax;
	bForceFullCooldown = false;
	setHealthState(EHS_Excellent);
}


/*This Function is called after the AnimTre is initialized.
*Any nodes that we want to control code, we should look up here.
*/
	/*simulated event PostInitAnimTree(SkeletalMeshComponent SkelComp)
	{
		super.PostInitAnimTree(SkelComp);
		if (SkelComp == Mesh)
		{
			IdleBlend = AnimNodeBlendBySpeed(Mesh.FindAnimNode('blendBySpeedNode'));
			AttackBlend = AnimNodePlayCustomAnim(Mesh.FindAnimNode('AttackBlend'));
			SwingBlend = AnimNodeBlendPerBone(Mesh.FindAnimNode('SwingBlend'));
			AttackAnim = AnimNodeSequence(Mesh.FindAnimNode('AttackAnim'));
		}
	}*/

/** Change the type of weapon animation we are playing. */
/*simulated function SetWeapAnimType(EWeapAnimType AnimType)
{
	if (AimNode != None)
	{
		switch(AnimType)
		{
			case EWAT_Default:
				AimNode.SetActiveProfileByName('Default');
				break;
			case EWAT_Pistol:
				AimNode.SetActiveProfileByName('SinglePistol');
				break;
			case EWAT_DualPistols:
				AimNode.SetActiveProfileByName('DualPistols');
				break;
			case EWAT_ShoulderRocket:
				AimNode.SetActiveProfileByName('ShoulderRocket');
				break;
			case EWAT_Stinger:
				AimNode.SetActiveProfileByName('Stinger');
				break;
		}
	}
}*/

/*
simulated function SetHealthAnimType(EHealthState AnimType)
{
	if (AimNode != None)
	{
		switch(AnimType)
		{
			case EHS_Excellent:
				AimNode.SetActiveProfileByName('Excellent');
				break;
			case EHS_Fair:
				AimNode.SetActiveProfileByName('Fair');
				break;
			case EHS_Bad:
				AimNode.SetActiveProfileByName('Bad');
				break;
			case EHS_Dead:
				break;
		}
	}
}
*/

event TakeDamage(int Damage, Controller InstigatedBy, vector HitLocation, vector Momentum, class<DamageType> DamageType, optional TraceHitInfo HitInfo, optional Actor DamageCauser)
{
	//local int OrigHealth;This is for keeping track of health before damage if we need it for calculations
	//OrigHealth = Health;
	Super.TakeDamage(Damage, InstigatedBy, HitLocation, Momentum, DamageType, HitInfo, DamageCauser);
	CheckHealthState();
	ClearTimer('StartRegenHealth');//Turn off any current regen so we can restart
	ClearTimer('IncrimentHealth');
	SetTimer(2.0, false, 'StartRegenHealth');
	//`log("begin regen health");
}

simulated function StartRegenHealth()//Sets health to recover itself over time
{
	if(Health < LocalHealthMax)
	{
		Health += 1;
		SetTimer(0.5, true, 'IncrimentHealth');
	}
}

simulated function IncrimentHealth()
{
	if(Health < LocalHealthMax)
	{
		Health += 1;
		//`log("health regened to "@Health);
		WorldInfo.Game.Broadcast(None, "health regened to "@Health);
	}
	else
	{
		ClearTimer('IncrimentHealth');
		//`log('Health is full at '@Health);
		WorldInfo.Game.Broadcast(None, 'Health is full at '@Health);
	}
}

function CheckHealthState()
{
	switch(CurrentHealthState)
	{
		//find the current health state based on the enums and check to see if we dropped below min health
		case EHS_Excellent:
		
			
			
			if(Health < ExcellentMinHealth)
			{
				setHealthState(EHS_Fair);
				BlackDeathPawn(Instigator).HealthState.SetActiveChild(1,0.0);
				
			}
			else
			{
				break;
			}
		case EHS_Fair:
			if(health < FairMinHealth)
			{
				setHealthState(EHS_Bad);
				BlackDeathPawn(Instigator).HealthState.SetActiveChild(2,0.0);
			}
			else
			{
				BlackDeathPawn(Instigator).HealthState.SetActiveChild(0,0.0);
				break;
			}
		case EHS_Bad:
			if(health <= 0)
			{
				setHealthState(EHS_dead);
			}
			else
			{
				break;
			}
		case EHS_Dead:
			break;
	}
}

simulated function setHealthState(EHealthState newState)
{
	if(CurrentHealthState != newState)
	{
		ResetDamageTilt();
		switch(newState)
		{
			case EHS_Excellent: LocalHealthMax = HealthMax; break;
			case EHS_Fair: LocalHealthMax = ExcellentMinHealth -1; break;
			case EHS_Bad: LocalHealthMax = FairMinHealth-1; break;
			case EHS_Dead: LocalHealthMax = 0; break;
		}
		CurrentHealthState = newState;
		//SetHealthAnimType(newState)
		`log("Health state is now"@newState);
	}
}

/*
simulated function bool CalcCamera( float fDeltaTime, out vector out_CamLoc, out rotator out_CamRot, out float out_FOV )
{
	local vector Loc, InitialLoc, HitLocation, HitNormal;
	local bool bHide;
	local int DamageTilt;
	//local Rotator Rot;
		//Note the setHerocam() Function in UTPawn for some hero cam stuff in the future
		/*CurrentCamOffset = CamOffset;
		
		InitialLoc = Location;
		InitialLoc.Z += CurrentCamOffset.Z;

		Loc = InitialLoc;
		Loc.X -= CurrentCamOffset.X*cos(Controller.Rotation.Yaw* 0.0000958738)*cos(Controller.Rotation.Pitch* 0.0000958738);
		Loc.Y -= CurrentCamOffset.X*sin(Controller.Rotation.Yaw* 0.0000958738)*cos(Controller.Rotation.Pitch* 0.0000958738);
		Loc.Z += CurrentCamOffset.X*sin(Controller.Rotation.Pitch* -0.0000958738);
		//couldn't figure out y displacement
		out_CamLoc = Loc;
		if (Trace(HitLocation, HitNormal, out_CamLoc, InitialLoc, false, vect(12,12,12),, TRACEFLAG_Blocking) != none)
		{
			out_CamLoc = HitLocation;
		}*/
		
		DamageTilt = CalcDamageTilt();
		out_camRot = Controller.Rotation;//Camera looks where the player points
		
		if(out_camRot.roll != DamageTilt)
		{
			out_camRot.roll = Lerp(out_camRot.roll,DamageTilt,0.15);
		}
		/*
		InitialLoc = Location;
		Loc=out_CamLoc;
		if (Trace(HitLocation, HitNormal, Loc, InitialLoc, false, vect(12,12,12),, TRACEFLAG_Blocking) != none)
		if((Loc.Z<Location.Z+CylinderComponent.CollisionHeight+80)&&VSize(HitLocation-InitialLoc)<GetCollisionRadius()*1.1)
		{
			bHide = true;
		}
		else
		{
			bHide = false;
		}
		if(bHide != isHidden)
		{
			ChangeVisibility(!bHide);
			isHidden = bHide;
		}*/
		//CurrentCamLoc = out_CamLoc;//put rot and loc into global varibles
		//CurrentCamRot = out_camRot;
		return Super.CalcCamera( fDeltaTime, out_CamLoc, out_CamRot, out_FOV );
	/*
	GetAxes(Rot, CamDirX, CamDirY, CamDirZ);
	CurrentCamOffset.X=140.0;CurrentCamOffset.Y=-0.3;CurrentCamOffset.Z=30.0;
	Loc = CamStart - CurrentCamOffset.Z*CamDirZ;// +CurrentCamOffset.X*CamDirX + CurrentCamOffset.Y*CamDirY;
	Loc.X -= CurrentCamOffset.X*cos(Controller.Rotation.Yaw* 0.0000958738+CurrentCamOffset.Y);
	Loc.Y -= CurrentCamOffset.X*sin(Controller.Rotation.Yaw* 0.0000958738+CurrentCamOffset.Y);
	SimpCam, fixed Z cordinants, might be preferable for something
	*/
}*/

simulated function float CalcDamageTilt()//Sets how much the camera should tilt based on the player's health.
{
	if(LocalHealthMax <= 0)
	{
		return 0.f;
	}
	return Abs(Health-LocalHealthMax)/LocalHealthMax*10430.37826809827*TiltDamageScale;
}

simulated function ResetDamageTilt()//LocalHealthMax
{
	CurrentCamRot.roll = 0;
}


/** running functions and controls */
State Running
{
	event BeginState(Name PreviousStateName)
	{
		if(Stamina <= 0)//If we ran out of stamina before the run started.
		{
			goToState('');
		}
		else
		{
			`log("run started");
			AirSpeed=300.000000;
			GroundSpeed=150.000000;
			if(BlackDeathCamera(PlayerController(Controller).PlayerCamera) != none)
			{
				BlackDeathCamera(PlayerController(Controller).PlayerCamera).ToggleRunning();
			}
			SetTimer(0.1, true, 'DecrementStamina');
		}
	}
	
	function EndRun()
	{
		goToState('');
	}
	
	function bool CanRun()
	{
		return false;//No dog, you can't put a run in your run
	}
	
	event EndState(Name NextStateName)
	{
		//`log("run ended");
		//consider adding a doRun() function to impliment the graphic effects of running aside from this low level stuff
		AirSpeed=150.000000;
		GroundSpeed=70.000000;
		if(BlackDeathCamera(PlayerController(Controller).PlayerCamera) != none)
		{
			BlackDeathCamera(PlayerController(Controller).PlayerCamera).ToggleRunning();
		}
		ClearTimer('DecrementStamina');
	}
}

simulated function StartRun()
{
	if(CanRun())//If we can run
	{
		goToState('running');
	}
}

simulated function EndRun()
{
}

function bool CanRun()
{
	return (Stamina > 0 && !bForceFullCooldown);
}


/** Stamina Functions and controls, go here for all stamina stuff, set Stamina manually and I will kill you! */
function DecreaseStamina(int Amount)
{
	if(Stamina > 0 /*&& !bForceFullCooldown*/)
	{
		Stamina -= Amount;
		Stamina = Max(Stamina, 0);
	}
	else
	{
		Stamina = 0;
	}
	if(Stamina <= 0)
	{
		ForceStaminaCoolDown();
	}
	StartRegenStamina();
}

function DecrementStamina()
{
	DecreaseStamina(1);
	`log("Stamina decriment and is: "@Stamina);
}

function StartRegenStamina()//Called to start regerating stamina
{
	EndReginStamina();
	SetTimer(3.0, false, 'BeginRecoverStamina');
}

function BeginRecoverStamina()
{
	RecoverStamina();
	if(Stamina < StaminaMax)
	{
		SetTimer(0.2, true, 'RecoverStamina');
	}
}

function EndReginStamina()
{
	clearTimer('RecoverStamina');
	clearTimer('BeginRecoverStamina');
}

function RecoverStamina()//Called to incriment stamina while running
{
	if(Stamina < StaminaMax)
	{
		`log("Stamina incrimented and is: "@Stamina);
		Stamina +=1;
	}
	else
	{
		EndReginStamina();
	}
	if(Stamina >= 50)
	{
		if(bForceFullCooldown)
		{
			`log("Stamina unfrozen");
			bForceFullCooldown = false;//Release the run lock
		}
	}
}

function ForceStaminaCoolDown()//function to handle when we run out of stamina
{
	ClearTimer('DecrementStamina');//dont decrease stamina anymore
	`log('Stamina froozen');
	bForceFullCooldown = true;//Lock running
	EndRun();//full stop to cancel running
	StartRegenStamina();
}


/** Aiming functions and controls */
simulated function ToggleAim()
{
	goToState('Aiming');
}

simulated function bool canAim()
{
	return true;
}

State Aiming
{
	event BeginState(Name PreviousStateName)
	{
		`log("Aiming State entered");
		AirSpeed=75.000000;
		GroundSpeed=75.000000;
		bJumpCapable = false;
		PlayerController(Controller).SetCameraMode('ThirdPerson');
	}
	
	simulated function bool canAim()
	{
		return False;
	}
	
	simulated function ToggleAim()
	{
		goToState('');
	}
	
	
	simulated function name GetDefaultCameraMode(PlayerController RequestedBy)
	{
		return 'ThirdPerson';
	}
	
	event EndState(Name NextStateName)
	{
		`log("aiming state left");
		AirSpeed=150.000000;
		GroundSpeed=70.000000;
		bJumpCapable = true;
		PlayerController(Controller).SetCameraMode('FollowCam');
	}
}

simulated function PlayDying(class<DamageType> DamageType, vector HitLoc)
{
  Super.PlayDying(DamageType, HitLoc);
  Health = 0;
  CheckHealthState();
  clearTimer('RecoverStamina');
}

DefaultProperties
{
	InventoryManagerClass=class'BlackDeathInventoryManager'
//Setting up the light environment
//Setting up the mesh and animset components
    Begin Object Name=InitialSkeletalMesh
        CastShadow=true
        bCastDynamicShadow=true
        bOwnerNoSee=false
        LightEnvironment=MyLightEnvironment;
		BlockRigidBody=true;
		CollideActors=true;
		BlockZeroExtent=true;
//What to change if you'd like to use your own meshes and animations
        PhysicsAsset=PhysicsAsset'BD_CHARACTERS.Mesh.Vincent_Physics'
        AnimSets(0)=AnimSet'BD_CHARACTERS.Animation.Vincent_MoveSet'
        AnimSets(1)=AnimSet'BD_CHARACTERS.Animation.VincentMoveSet'
        AnimTreeTemplate=AnimTree'BD_CHARACTERS.Animation.Human_AnimTree'
        SkeletalMesh=SkeletalMesh'BD_CHARACTERS.Mesh.Vincent'
    End Object
//Setting up a proper collision cylinder
    Mesh=InitialSkeletalMesh;
    Components.Add(InitialSkeletalMesh); 
	CollisionType=COLLIDE_BlockAll
	Begin Object Name=CollisionCylinder
		CollisionRadius=+0024.000000
		CollisionHeight=+0044.000000
	End Object
	CylinderComponent=CollisionCylinder
	
	TiltDamageScale = 1.5
	HealthMax = 100
	ExcellentMinHealth = 67
	FairMinHealth = 34
	StaminaMax = 100
	
	UseableCheckRadius = 75
	
	AirSpeed=150.000000
	GroundSpeed=70.000000
	bCanCrouch=true
	bCanClimbLadders=True
	bCanPickupInventory=True
	bCanBeDamaged=true
	bCanSwim=true
	
	InitialInventory(0)=class'BD_Fists'
	InitialInventory(1)=class'BDMelee_Torch'
	InitialInventory(2)=class'BDMelee_GreatSword'
	
	WeaponSocket=WeaponPoint
	SwordHolderSocket = TestHolder
}
